package com.biz.primus.ms.depot.service;

import com.biz.primus.base.enums.CommonStatus;
import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.common.utils.CopyUtils;
import com.biz.primus.common.utils.DateUtil;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.model.depot.exception.DepotException;
import com.biz.primus.model.depot.vo.*;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.depot.dao.po.QrCode;
import com.biz.primus.ms.depot.dao.po.WeChatLog;
import com.biz.primus.ms.depot.dao.redis.QrCodeRedisDao;
import com.biz.primus.ms.depot.dao.repository.EmpSpreadRepository;
import com.biz.primus.ms.depot.dao.repository.QrCodeRepository;
import com.biz.primus.ms.depot.dao.repository.WeChatLogRepository;
import com.biz.primus.ms.depot.dao.ro.QrCodeRo;
import com.biz.primus.ms.depot.dao.specfication.QrCodeSpecfication;
import com.biz.primus.ms.depot.trans.QrCode2Ro;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * QrCodeService
 *
 * @author JKLiues
 * @date 2017年11月07日
 */
@Service
@Slf4j
public class QrCodeService extends AbstractBaseService {
    private final QrCodeRepository qrCodeRepository;
    private final QrCodeRedisDao qrCodeRedisDao;
    private final WeChatLogRepository weChatLogRepository;

    @Autowired
    public QrCodeService(QrCodeRepository qrCodeRepository,
                         QrCodeRedisDao qrCodeRedisDao,
                         WeChatLogRepository weChatLogRepository) {
        this.qrCodeRepository = qrCodeRepository;
        this.qrCodeRedisDao = qrCodeRedisDao;
        this.weChatLogRepository = weChatLogRepository;
    }

    /**
     * 后台分页查询二维码
     *
     * @param reqVo 分页请求对象
     */
    public SpringPageVO<QrCodeBackendListRespVo> pageResult(QrCodeBackendPageReqVo reqVo) {
        Page<QrCode> all = qrCodeRepository.findAll(new QrCodeSpecfication(reqVo), reqVo.toPageRequest());
        return SpringPageToSpringPageVO.of(all, (po) -> {
            QrCodeBackendListRespVo vo = new QrCodeBackendListRespVo();
            CopyUtils.copyProperties(po, vo);
            return vo;
        });
    }

    /**
     * 保存更新二维码
     *
     * @param reqVo 请求VO
     */
    @Transactional(rollbackFor = Exception.class)
    public void save(QrCodeUpdateVo reqVo) {
        this.validate(reqVo);
        QrCode po = new QrCode();
        CopyUtils.copyProperties(reqVo, po);
        if (po.getId() == null) {
            po.setId(idService.getNextId());
        }
        qrCodeRepository.save(po);
        QrCodeRo apply = new QrCode2Ro().apply(po);
        delayer.executeAfterTransactionCommit(() -> qrCodeRedisDao.save(apply));
    }

    /**
     * 二维码详情
     *
     * @param id id
     */
    public QrCodeUpdateVo detail(Long id) {
        QrCode one = qrCodeRepository.findOne(id);
        AssertUtils.notNull(one, DepotException.QR_CODE_NOT_EXISTS);
        QrCodeUpdateVo vo = new QrCodeUpdateVo();
        CopyUtils.copyProperties(one, vo);
        return vo;
    }

    /**
     * 逻辑删除
     *
     * @param id id
     */
    public void disable(Long id) {
        QrCode qrCode = qrCodeRepository.findOne(id);
        AssertUtils.notNull(qrCode, DepotException.QR_CODE_NOT_EXISTS);
        Timestamp beginTime = qrCode.getBeginTime();
        Timestamp endTime = qrCode.getEndTime();
        boolean nowBetween = DateUtil.isNowBetween(beginTime, endTime);
        if (!nowBetween) {
            qrCodeRedisDao.removeFromEffective(qrCode.getId());
        }
        qrCode.setStatus(CommonStatus.DISABLE);
        qrCodeRepository.save(qrCode);
        QrCodeRo apply = new QrCode2Ro().apply(qrCode);
        delayer.executeAfterTransactionCommit(() -> qrCodeRedisDao.save(apply));
    }

    /**
     * 每天同步当天生效的二维码到redis set
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void sync() {
        List<QrCode> pos = qrCodeRepository.findByDateAndStatus(DateUtil.now(), CommonStatus.ENABLE);
        List<Long> ids = Optional.ofNullable(pos).orElse(new ArrayList<>()).stream()
                .map(QrCode::getId).collect(Collectors.toList());
        qrCodeRedisDao.initAndSetEffective(ids);
    }

    /**
     * 查询当天生效的二维码
     */
    public List<QrCodeListRespVo> getAllEffective() {
        List<QrCodeRo> ros = qrCodeRedisDao.getEffective();
        return Optional.ofNullable(ros).orElse(new ArrayList<>()).stream()
                .map(ro -> new QrCodeListRespVo(ro.getType(), buildUrl(ro)))
                .collect(Collectors.toList());
    }

    /**
     * 处理微信推送事件
     *
     * @param vo 事件
     */
    public void handleWeChatEvent(WeChatEventVo vo) {
        String event = vo.getEvent();
        String scenceId;
        switch (event) {
            case "subscribe":
                String eventKey = vo.getEventKey();
                String fromUserName = vo.getFromUserName();
                String[] split = eventKey.split("_");
                if (split.length < 1) {
                    log.error("数据异常{}", vo);
                    return;
                }
                scenceId = split[1];
                WeChatLog weChatLog = new WeChatLog();
                weChatLog.setId(idService.getNextId());
                weChatLog.setEvent(event);
                weChatLog.setFromUser(scenceId);
                weChatLog.setOpenId(fromUserName);
                weChatLogRepository.save(weChatLog);
                log.info("接受到{}关注信息 from:{}", fromUserName, scenceId);
                break;
            default:
                log.error("暂不支持事件类型:{}", event);
                return;
        }
    }

    /**
     * 二维码更新参数校验
     *
     * @param reqVo 校验参数
     */
    private void validate(QrCodeUpdateVo reqVo) {
//
//        String qrCode = reqVo.getQrCode();
//        QrTypeEnum type = reqVo.getType();
//        Timestamp beginTime = reqVo.getBeginTime();
//        Timestamp endTime = reqVo.getEndTime();
//        Long relationId = reqVo.getRelationId();

    }

    /**
     * 构造二维码的地址
     *
     * @param ro 二维码对象
     */
    private String buildUrl(QrCodeRo ro) {
        return null;
    }
}